home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 February: Tool Chest / Dev.CD Feb 94.toast / New System Software Extensions / QuickDraw™ GX v1.0ß2 / Interfaces & Libraries / printing libraries / PicturesAndPICTLibrary.c < prev   
Encoding:
C/C++ Source or Header  |  1993-07-31  |  13.2 KB  |  457 lines  |  [TEXT/MPS ]

  1. /*
  2.     Libraries for dealing with pictures within PICTs
  3.     copyright © 1992 Apple Computer, Inc.
  4.     All rights reserved.
  5.     
  6.     
  7.     Routines in this library:
  8.         PictureToPICT         - creates a PICT with an embedded picture shape
  9.         DrawPictureOrProxy    - renders a PICT created with the above call
  10. */
  11. #include <Types.h>
  12. #include <QuickDraw.h>
  13. #include <ToolUtils.h>
  14. #include <Memory.h>
  15.  
  16. #include "graphics routines.h"
  17. #include "graphics toolbox.h"
  18. #include "math routines.h"
  19. #include "storage library.h"
  20. #include "offscreen library.h"
  21. #include "qd library.h"
  22.  
  23. pascal void DoDrawPicture(PicHandle myPicture,const Rect *dstRect)
  24.     = 0xA8F6; 
  25.  
  26. //-----------------------------------------------------------------------------
  27. // INTERNAL TYPEDEFS AND DEFINES
  28. //-----------------------------------------------------------------------------
  29.  
  30. // IDs for the PicComments
  31. #define shapeSignature    'shpe'
  32. #define shapeBegin        500
  33. #define shapeEnd        501
  34.  
  35. // typedefs for the new PicComments
  36. typedef struct 
  37.     {
  38.     OSType        signature;        // always == shapeSignature
  39.     short        kind;            // always == shapeBegin
  40.     Rect        bounds;            // bounds of shape @ 72 dpi
  41.     char        data[1];        // flattened shape data, total size of record determines
  42.                                 // size
  43.     } ShapeBeginRecord, *ShapeBeginPtr, **ShapeBeginHdl;
  44.     
  45. typedef struct
  46.     {
  47.     OSType        signature;        // always == shapeSignature
  48.     short        kind;            // always == shapeEnd
  49.     } ShapeEndRecord, *ShapeEndPtr, **ShapeEndHdl;
  50.  
  51. // calling conventions for a comment bottleneck
  52. typedef pascal void (*CommentProcPtr)(short kind, short dataSize, Handle dataHandle);
  53.     
  54. //-----------------------------------------------------------------------------
  55. // GLOBAL VARIABLES
  56. //-----------------------------------------------------------------------------
  57. short        gAmRendering;                    // are we handing rendering through GX?
  58. short        gWereProcsInstalled;            // were there already procs installed, or did we add them?
  59.  
  60. Rect        gPicFrame;                        // original size of picture
  61. Rect        gDestRect;                        // new size of picture
  62. CQDProcs    gSavedProcs;                    // if there were procs installed, we save them here
  63.  
  64. //-----------------------------------------------------------------------------
  65. // INTERNAL ROUTINES
  66. //-----------------------------------------------------------------------------
  67. pascal void NilTextBottleneck(short, Ptr, Point, Point)
  68. /*
  69.     This bottleneck just NOPs out anything passing through it.
  70. */
  71. {
  72.     return;
  73.     
  74. } // NilTextBottleneck
  75. /* ------------------------------------------------------------------------    */
  76.  
  77. pascal void NilLineBottleneck(Point)
  78. /*
  79.     This bottleneck just NOPs out anything passing through it.
  80. */
  81. {
  82.     return;
  83.     
  84. } // NilLineBottleneck
  85.  
  86. /* ------------------------------------------------------------------------    */
  87.  
  88. pascal void NilRectBottleneck(GrafVerb, Rect)
  89. /*
  90.     This bottleneck just NOPs out anything passing through it.
  91. */
  92. {
  93.     return;
  94.     
  95. } // NilRectBottleneck
  96.  
  97. /* ------------------------------------------------------------------------    */
  98.  
  99. pascal void NilRRectBottleneck(GrafVerb, Rect, short, short)
  100. /*
  101.     This bottleneck just NOPs out anything passing through it.
  102. */
  103. {
  104.     return;
  105.     
  106. } // NilRRectBottleneck
  107.  
  108. /* ------------------------------------------------------------------------    */
  109.  
  110. pascal void NilPolyBottleneck(GrafVerb, Handle)
  111. /*
  112.     This bottleneck just NOPs out anything passing through it.
  113. */
  114. {
  115.     return;
  116.     
  117. } // NilPolyBottleneck
  118.  
  119. /* ------------------------------------------------------------------------    */
  120.  
  121. pascal void NilBitsBottleneck(BitMap *, Rect *, Rect *, short, Handle)
  122. /*
  123.     This bottleneck just NOPs out anything passing through it.
  124. */
  125. {
  126.     return;
  127.     
  128. } // NilBitsBottleneck
  129.  
  130. /* ------------------------------------------------------------------------    */
  131.  
  132. pascal void RenderComment(short kind, short dataSize, Handle dataHandle)
  133. /*
  134.     This bottleneck routine gets called to detect the shapeBegin/shapeEnd pairs.
  135.     Within these pairs, all other bottlenecks will be NOPed out, and we'll
  136.     draw QuickDraw GX data instead.
  137. */
  138. {
  139.     GrafPtr            curPort;
  140.     CQDProcsPtr        grafProcs;
  141.     gxShape            theShape;
  142.     
  143.     GetPort(&curPort);
  144.  
  145.     switch (kind)
  146.         {
  147.         case shapeBegin:
  148.             // when we see the start comment, stop all QuickDraw drawing via the bottlenecks
  149.             grafProcs = (CQDProcsPtr) qd.thePort->grafProcs;
  150.             grafProcs->textProc        = (Ptr) NilTextBottleneck;
  151.             grafProcs->lineProc        = (Ptr) NilLineBottleneck;
  152.             grafProcs->rectProc        = (Ptr) NilRectBottleneck;
  153.             grafProcs->rRectProc    = (Ptr) NilRRectBottleneck;
  154.             grafProcs->ovalProc        = (Ptr) NilRectBottleneck;
  155.             grafProcs->arcProc        = (Ptr) NilRRectBottleneck;
  156.             grafProcs->polyProc        = (Ptr) NilPolyBottleneck;
  157.             grafProcs->rgnProc        = (Ptr) NilPolyBottleneck;
  158.             grafProcs->bitsProc        = (Ptr) NilBitsBottleneck;
  159.                 
  160.             // We now are in charge of this grafPort
  161.             gAmRendering = true;
  162.  
  163.             // remove the header from the shape data            
  164.             Munger(dataHandle, 0, nil, sizeof(OSType) + sizeof(short) + sizeof(Rect), (Ptr)2, 0);
  165.                         
  166.             
  167.             // place the shape within the current window    
  168.             {
  169.             gxViewPort    windowViewPort = GXGetWindowViewPort(FrontWindow());
  170.             
  171.             theShape = HandleToShape(dataHandle, 1, &windowViewPort );
  172.             }
  173.             
  174.             // move the shape into the correct position of the window
  175.             {
  176.             gxShape        clipShape;
  177.             gxRectangle    clipRect;
  178.             
  179.             GXScaleTransform(GXGetShapeTransform(theShape), 
  180.                 FixRatio(gDestRect.right - gDestRect.left,     gPicFrame.right - gPicFrame.left),
  181.                 FixRatio(gDestRect.bottom - gDestRect.top,     gPicFrame.bottom - gPicFrame.top),
  182.                 0, 0);
  183.             GXMoveShapeTo(theShape, ff(gDestRect.left), ff(gDestRect.top) );
  184.             
  185.             // clip against the draw area
  186.             clipRect.left     = ff(gDestRect.left);
  187.             clipRect.top     = ff(gDestRect.top);
  188.             clipRect.right     = ff(gDestRect.right);
  189.             clipRect.bottom = ff(gDestRect.bottom);
  190.             clipShape = GXNewRectangle(&clipRect);
  191.             GXSetShapeClip(theShape, clipShape);
  192.             GXDisposeShape(clipShape);
  193.             }
  194.             
  195.             // finally, draw the data and get rid of it once done
  196.             GXDrawShape(theShape);
  197.             GXDisposeShape(theShape);
  198.  
  199.             break;
  200.             
  201.         case shapeEnd:
  202.             
  203.             // when we see the end comment, we restore all of the bottlenecks
  204.             grafProcs = (CQDProcsPtr) qd.thePort->grafProcs;
  205.             grafProcs->textProc        = gSavedProcs.textProc;
  206.             grafProcs->lineProc        = gSavedProcs.lineProc;
  207.             grafProcs->rectProc        = gSavedProcs.rectProc;
  208.             grafProcs->rRectProc    = gSavedProcs.rRectProc;
  209.             grafProcs->ovalProc        = gSavedProcs.ovalProc;
  210.             grafProcs->arcProc        = gSavedProcs.arcProc;
  211.             grafProcs->polyProc        = gSavedProcs.polyProc;
  212.             grafProcs->rgnProc        = gSavedProcs.rgnProc;
  213.             grafProcs->bitsProc        = gSavedProcs.bitsProc;
  214.                 
  215.             // we're detached from the bottlenecks now
  216.             gAmRendering = false;
  217.             break;
  218.             
  219.         default:
  220.             // if we aren't rendering GX data yet, let the comment proc go through
  221.             if ( !(gAmRendering) )
  222.                 {
  223.                 if (gWereProcsInstalled)
  224.                     {
  225.                     // use the previously installed comment
  226.                     grafProcs = (CQDProcsPtr) qd.thePort->grafProcs;
  227.                     
  228.                     (* (CommentProcPtr) (gSavedProcs.commentProc)) (kind, dataSize, dataHandle);
  229.                     }
  230.                 else
  231.                     {
  232.                     // use the ROM comment proc - not that it normally does anything
  233.                     StdComment(kind, dataSize, dataHandle);
  234.                     }
  235.                 }
  236.             break;
  237.             
  238.         } // switch (kind)
  239.         
  240. } // RenderComment
  241.  
  242. //-----------------------------------------------------------------------------
  243. // EXTERNAL ROUTINES
  244. //-----------------------------------------------------------------------------
  245. void    DrawPictureOrProxy(PicHandle hPicture, Rect *dstRect)
  246. /*
  247.     This library routine demonstrates how to render a picture, such that GX proxies
  248.     (as generated through PictureToPICT) are rendered using GX rather than QuickDraw.
  249.     
  250.     This routine works by installing QuickDraw bottlenecks that interpret the data
  251.     in the PicComments to determine when GX data is to be used.
  252.     
  253.     This call assumes that a valid QuickDraw window exists, and that it has a valid
  254.     window viewPort - created by calling NewWindowViewPort.
  255. */
  256. {
  257.     
  258.     // so far, no GX data
  259.     gAmRendering = false;
  260.     
  261.     // remember where picture is being drawn (offset by the origin)
  262.     gPicFrame     = (**hPicture).picFrame;
  263.     gDestRect     = *dstRect;
  264.     OffsetRect(&gDestRect, -qd.thePort->portRect.left, -qd.thePort->portRect.top);
  265.     
  266.     // are there existing procs?
  267.     if (qd.thePort->grafProcs != nil)
  268.         {
  269.         // remember that there were orginally bottlenecks
  270.         gWereProcsInstalled = true;
  271.         
  272.         // save the old procs away
  273.         gSavedProcs = *((CQDProcs*)qd.thePort->grafProcs);
  274.         
  275.         // install our StdComment proc
  276.         qd.thePort->grafProcs->commentProc = (Ptr) RenderComment;
  277.         }
  278.     else
  279.         {
  280.         // no existing procs, so install new bottlenecks
  281.         gWereProcsInstalled = false;
  282.         
  283.         // install the standard procs
  284.         if (qd.thePort->portBits.rowBytes & 0x80000000)
  285.             SetStdCProcs(&gSavedProcs);
  286.         else
  287.             SetStdProcs((QDProcs*) &gSavedProcs);
  288.             
  289.         // and a custom comment proc
  290.         gSavedProcs.commentProc = (Ptr) RenderComment;
  291.         
  292.         // stick the procs into the port
  293.         qd.thePort->grafProcs = (QDProcs*) &gSavedProcs;
  294.         }
  295.         
  296.     // render the data
  297.     DoDrawPicture(hPicture, dstRect);
  298.     
  299.     if (gWereProcsInstalled)
  300.         {
  301.         
  302.         // if there were originally bottlenecks in the port, replace them
  303.         if (qd.thePort->portBits.rowBytes & 0x80000000)
  304.             *(((CGrafPtr)qd.thePort)->grafProcs) = gSavedProcs;
  305.         else
  306.             *(qd.thePort->grafProcs) = * ((QDProcs*) &gSavedProcs);
  307.         }
  308.     else
  309.         {
  310.         
  311.         // deinstall our bottlenecks
  312.         qd.thePort->grafProcs = nil;
  313.         }
  314.                 
  315. } // DrawPictureOrProxy
  316.  
  317. //-----------------------------------------------------------------------------
  318. PicHandle    PictureToPICT(gxShape theShape, Boolean simpleProxy)
  319. /*
  320.     This library routine turns a QuickDraw GX™ shape into a QuickDraw PICT.
  321.     It does this using three steps:
  322.         1)  it emits a QuickDraw PicComment, and places the flattened GX data into
  323.             the comment.
  324.         2)    it converts the GX picture into a QuickDraw proxy.  It uses a rectangle
  325.             with an 'X' through it if simpleProxy is true.  Otherwise, it uses a 1 bit
  326.             bitmap rendition of the shape.
  327.         3)    it emits a QuickDraw PictComment, marking the end of the QuickDraw proxy.
  328.         
  329.     The resulting PICT can be cut & pasted, or saved into a PICT file.  On a system
  330.     with QuickDraw GX™ installed, the GX data will be used when printing.  
  331.     When printing on other systems, the QuickDraw proxy will be used.
  332.     
  333.     The proxy is always used for display from within non-GX applications.
  334. */
  335. {
  336.     gxGraphicsError        gxErr = noErr;
  337.     PicHandle            thePicture;
  338.     Rect                picRect;
  339.     ShapeBeginRecord    theBegin;
  340.     Handle                hBegin;
  341.     ShapeEndHdl            hEnd;
  342.     gxRectangle            shapeBounds;
  343.         
  344.     // get the location of the shape
  345.     GXGetShapeDeviceBounds(theShape, 0, 0, &shapeBounds);    
  346.     picRect.left     = FixedToInt(shapeBounds.left);
  347.     picRect.top     = FixedToInt(shapeBounds.top);
  348.     picRect.right     = FixedToInt(shapeBounds.right);
  349.     picRect.bottom     = FixedToInt(shapeBounds.bottom);
  350.     GlobalToLocal((Point*) &picRect.top);
  351.     GlobalToLocal((Point*) &picRect.bottom);
  352.         
  353.     thePicture = OpenPicture(&picRect);
  354.     if (thePicture != nil)
  355.         {
  356.         // flatten our shape out into a handle
  357.         hBegin = ShapeToHandle(theShape);
  358.         if (hBegin != nil)
  359.             {
  360.             // add the comment to the begining of the handle
  361.             theBegin.signature     = shapeSignature;
  362.             theBegin.kind         = shapeBegin;
  363.             theBegin.bounds     = picRect;
  364.             Munger(hBegin, 0, nil, 0, &theBegin, sizeof(OSType) + sizeof(short) + sizeof(Rect) );
  365.             gxErr = MemError();
  366.         
  367.             // store the shape/handle into the picture
  368.             PicComment(shapeBegin, GetHandleSize(hBegin), hBegin);
  369.             DisposHandle(hBegin);
  370.             
  371.             }
  372.         else
  373.             gxErr = MemError();
  374.     
  375.         if (gxErr == noErr)
  376.             {
  377.             if (simpleProxy)
  378.                 {
  379.                 // our proxy is just a framed rect with an X through it
  380.                 FrameRect(&picRect);
  381.                 MoveTo(picRect.left,     picRect.top);
  382.                 LineTo(picRect.right,     picRect.bottom);
  383.                 MoveTo(picRect.right,     picRect.top);
  384.                 LineTo(picRect.left,     picRect.bottom);
  385.                 }
  386.             else
  387.                 {
  388.                 // our proxy is a bitmap of the GX object
  389.                 gxBitmap        theBits;
  390.                 gxShape            theBitmap;
  391.  
  392.                 theBits.width         = picRect.right - picRect.left;
  393.                 theBits.height         = picRect.bottom - picRect.top;
  394.                 theBits.pixelSize     = 1;
  395.                 theBits.rowBytes    = ( ( theBits.width >> 3 ) + 3 ) & ~0x3;
  396.                 theBits.image         = NewPtrClear(theBits.height * theBits.rowBytes);
  397.                 theBits.space         = gxIndexedSpace;
  398.                 theBits.set         = nil;
  399.                 theBits.profile     = nil;
  400.                 
  401.                 gxErr = MemError();
  402.                 if (gxErr == noErr);
  403.                     {
  404.                     theBitmap = GXNewBitmap(&theBits, nil);
  405.                     GXMoveTransformTo(GXGetShapeTransform(theBitmap), -shapeBounds.left, -shapeBounds.top);
  406.                     GXGetGraphicsError(&gxErr);
  407.                     if (gxErr == noErr)
  408.                         {
  409.                         BitMap        qdBits;
  410.                         
  411.                         // put the shape into the bitmap
  412.                         CopyToBitmaps(theBitmap, theShape);
  413.                         ConvertToQDBitmap(&theBits, &qdBits);
  414.                         GXGetGraphicsError(&gxErr);
  415.                                                                         
  416.                         // now done with the bitmap
  417.                         GXDisposeShape(theBitmap);
  418.  
  419.                         // CopyBits it into the picture
  420.                         CopyBits(&qdBits, &qd.thePort->portBits, &qdBits.bounds, &picRect, srcOr, nil);
  421.                         
  422.                         }
  423.                         
  424.                     // and done with the image
  425.                     DisposPtr(theBits.image);
  426.                     }
  427.                 }
  428.             
  429.             // mark the end of our shape's proxy
  430.             hEnd = (ShapeEndHdl) NewHandle(sizeof(ShapeEndRecord));
  431.             if (hEnd != nil)
  432.                 {
  433.                 (**hEnd).signature     = shapeSignature;
  434.                 (**hEnd).kind         = shapeEnd;
  435.                 PicComment(shapeEnd, GetHandleSize((Handle) hEnd), (Handle) hEnd);
  436.                 DisposHandle((Handle) hEnd);
  437.                 }
  438.             else
  439.                 gxErr = MemError();
  440.             }
  441.         
  442.         ClosePicture();
  443.         }
  444.     else
  445.         gxErr = MemError();
  446.         
  447.     // if we had a problem, return a nil picture
  448.     if ( ( gxErr != noErr ) && thePicture )
  449.         {
  450.         KillPicture(thePicture);
  451.         thePicture = nil;
  452.         }
  453.         
  454.     return(thePicture);
  455.     
  456. } // PictureToPICT
  457.